//
//  MessangerSprite.m
//  MessangerSkeleton
//
//  Created by User-16 on 4/1/14.
//  Copyright (c) 2014 IOTrainingCamp. All rights reserved.
//

#import "MessengerSprite.h"
#import "CCAnimation.h"


#import "cocos2d.h"
#import "cocos2d-ui.h"

#import "TransferSettings.h"
#import "AnimationLoader.h"

Interval MakeInterval(CGPoint begining, CGPoint end) {
    struct Interval range;
    range.begining = begining;
    range.end = end;
    return range;
}


@interface MessengerSprite ()


//animations
@property CCAction *runAction;
@property CCAction *jumpAction;
@property CCAction *slideAction;
@property CCAnimation* rollAnimation;

//offset of the physics body from the sprite
@property CGPoint offset;


//defined in header
@property(nonatomic, readwrite) MessengerSpriteType characterType;
@property (readwrite)int distance;
@property (nonatomic, readwrite) NSUInteger powerUpSpeedBoostCollectedItemsCount;
@property (nonatomic, readwrite) CGFloat secondsPassedSinceStart; //score
@property CGPoint currentSpeed;
@property CharacterState state;

//state variables
@property BOOL isSlidingOrJumping;
@property CharacterState previousState;

@property CCAnimation* runningAnim;
@property CCAction* slideAnim;



@end

@implementation MessengerSprite

#pragma mark - behaviours

-(void) run
{
    //set state
    self.isSlidingOrJumping = NO;
    self.state = kStateRunning;
    
    //delete previous state info
    [self stopAllActions];
    
    //run action
    [self runAction:self.runAction];
}

- (void) jump
{
    //don't allow double jump
    if(self.isSlidingOrJumping == YES) return;
    
    //clear previous state traces
    [self unschedule:@selector(restoreKikback)];
    
    
    if(self.state == kStateRunning || self.state == kStateBumpingBottom || self.state == kStateBumpingkStateBumpingFrontOrBack || self.state == kStateTurbo)
    {
        //set current state
        self.isSlidingOrJumping = YES;
        self.state = kStateJumping;
        
        //clear previous state
        [self stopAllActions];
        
        //act
        TransferSettings* transferedData = [TransferSettings sharedInstance];
        if (transferedData.soundsOn) {
            [[OALSimpleAudio sharedInstance] playEffect:kPreloadEffectJump];
        }
        
        [self runAction: [CCActionSequence actions: self.jumpAction,
                      [CCActionCallFunc actionWithTarget:self selector:@selector(restoreKikback)],
                    [CCActionCallFunc actionWithTarget:self selector:@selector(run)],
                      nil]];
    }
}

- (void) slide
{
    
    if(self.isSlidingOrJumping == YES) return;
    
    [self unschedule:@selector(restoreKikback)];
    
    self.isSlidingOrJumping = YES;
    if(self.state == kStateRunning || self.state == kStateBumpingBottom || self.state == kStateBumpingkStateBumpingFrontOrBack || self.state == kStateTurbo)
    {
    self.state = kStateSliding;
    TransferSettings* transferedData = [TransferSettings sharedInstance];
    if (transferedData.soundsOn) {
        [[OALSimpleAudio sharedInstance] playEffect:kPreloadEffectSlide];
    }
    [self stopAllActions];
    [self runAction: [CCActionSequence actions: self.slideAction,
                      [CCActionCallFunc actionWithTarget:self selector:@selector(restoreKikback)],
                      [CCActionCallFunc actionWithTarget:self selector:@selector(run)],
                      nil]];
    }
   
}


-(void) hitToFrontOrBack{
    
    //clear previous state
    [self unschedule:@selector(restoreKikback)];
    
    //act
    [self speedToKickback];
    if (self.state != kStateJumping){
        [self scheduleOnce:@selector(restoreKikback) delay:kMessengerKickbackDuration];
    }
    
    //set current state
    self.state = kStateBumpingkStateBumpingFrontOrBack;

}

-(void) hitToBottom{

    self.state = kStateBumpingBottom;
    [self stopAllActions];
    [self run];  
}

-(void) endHitToBottom{
        self.state = kStateFalling;
        [self stopAllActions];
        //position might not work for enemy!
        [self runAction: [CCActionSequence actions: [CCActionMoveTo actionWithDuration:kMessengerJumpDuration/2 position:ccp(self.position.x, self.spawnPoint.y)],
                      [CCActionCallFunc actionWithTarget:self selector:@selector(run)],
                      nil]]; 
}

-(void) hitToTop{

    self.state =  kStateBumpingTop;
    [self stopAllActions];
        //position might not work for enemy!
    [self runAction: [CCActionSequence actions: [CCActionMoveTo actionWithDuration:kMessengerJumpDuration/2 position:ccp(self.position.x, self.spawnPoint.y)],
                      [CCActionCallFunc actionWithTarget:self selector:@selector(run)],
                      nil]];   
}

-(void) collectPowerUpSpeedBoostItem {
    self.powerUpSpeedBoostCollectedItemsCount += 1;
    NSLog(@"%lu", (unsigned long)self.powerUpSpeedBoostCollectedItemsCount);
    [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationPlayerPowerUpChange object: nil];
}

-(void) turboBoost{
    [self unschedule:@selector(speedToNormal)];
    if (self.powerUpSpeedBoostCollectedItemsCount >= kMessengerPowerUpsNeededForTurbo){
        self.state = kStateTurbo;
        self.powerUpSpeedBoostCollectedItemsCount = 0;
        
        [self speedToTurbo];
        [self scheduleOnce:@selector(speedToNormal) delay:kMessengerTurboDuration];        
    }
}

#pragma mark - update

-(void)update:(CCTime)delta
{
    [self passSecondWithDelta:delta];
    self.distance += self.currentSpeed.x*delta;
}

#pragma mark - setters
-(void)setState:(CharacterState)state
{
    //remember previous action state
    if(self.state == kStateRunning || self.state == kStateJumping || self.state == kStateSliding)
        self.previousState = self.state;
    
    _state = state;
    NSLog(@"state: %d" , _state);
}


#pragma mark - initialization
- (id)initWithType:(MessengerSpriteType)type
{
    
    if (type == kMessengerSelf) {
        
        self = [super initWithSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:@"%@%d.png",kMessengerFileNameBase, 1]]];
    }
    //TODO add sprite sheet for the enemy and implement same for it -- added for testing purposes - rev13
    else{
        self = [super initWithSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:@"%@%d.png",kMessengerEnemyFileNameBase, 1]]];
    }
    
    if (self) {
        
        self.characterType = type;
        
        self.scale = kMessengerScale;
        
        // set the number of collected powerUps: 1) for speed
        self.powerUpSpeedBoostCollectedItemsCount = 0;
        
        //set the score timer
        self.secondsPassedSinceStart = 0;
        
        // set the messenger state
        self.currentSpeed = kMessengerInitialMaxSpeed;
        self.hitBottom = NO;
        self.isSlidingOrJumping = NO;
        
        [self initActionsAndAnimations];
        
        
        // setup the physics body

        self.offset = ccp(110, 80);
        self.front = MakeInterval(ccp(-20 + self.offset.x, -100 + self.offset.y), ccp(100 + self.offset.x, 150 + self.offset.y));
        self.back = MakeInterval(ccp(-83 + self.offset.x, -100 + self.offset.y), ccp(-68 + self.offset.x, -50 + self.offset.y));
        self.bottom = MakeInterval(ccp(-68 + self.offset.x, -100 + self.offset.y), ccp(-20 + self.offset.x, -50 + self.offset.y));
        self.up = MakeInterval(ccp(-83 + self.offset.x, -50 + self.offset.y), ccp(-20 + self.offset.x, 150 + self.offset.y));

        
        int num = 10;
        CGPoint* shapeArr = malloc(sizeof(CGPoint)*num);
        
        shapeArr[0] = ccp(25.2f, 30.2f);
        shapeArr[1] = ccp(32.1f, -20.0f);
        shapeArr[2] = ccp(29.4f, -37.5f);
        shapeArr[3] = ccp(27.4f, -52.8f);
        shapeArr[4] = ccp(23.9f, -59.4f);
        shapeArr[5] = ccp(3.6f, -66.6f);
        shapeArr[6] = ccp(-84.9f, -66.2f);
        shapeArr[7] = ccp(-1.3f, 36.6f);
        shapeArr[8] = ccp(9.5f, 38.6f);
        shapeArr[9] = ccp(22.4f, 35.4f);
        
        for(int i=0; i< num; i++)
        {
            shapeArr[i] = ccp(shapeArr[i].x + self.offset.x, shapeArr[i].y + self.offset.y);
        }
        
        double scale = 1.6;
        for(int i=0; i< num; i++)
        {
            shapeArr[i] = ccp(shapeArr[i].x*scale, shapeArr[i].y*scale);
        }	
        
        
        self.physicsBody = [CCPhysicsBody bodyWithPolygonFromPoints:shapeArr count:num cornerRadius:10];
        self.physicsBody.sensor = YES;
        self.physicsBody.collisionType = @"player";
        
        free(shapeArr);
        
        [self run];
    }
    return self;
}

#pragma mark - private methods

// init related
-(void) initActionsAndAnimations
{
    //initiate animations
    CCAnimation* runAnimation;
    CCAnimation* goInAnimation;
    CCAnimation* goOutAnimation;
    
    if (self.characterType == kMessengerSelf) {
        
        self.runningAnim = [AnimationLoader loadPlistForAnimationWithName:@"RunAnim" inFileNamed:@"BadGuyAnim"];
        runAnimation = [AnimationLoader loadPlistForAnimationWithName:@"RunAnim" inFileNamed:@"BadGuyAnim"];
        goInAnimation = [AnimationLoader loadPlistForAnimationWithName:@"GetInAnim" inFileNamed:@"BadGuyAnim"];
        goOutAnimation = [AnimationLoader loadPlistForAnimationWithName:@"GetOutAnim" inFileNamed:@"BadGuyAnim"];
        self.rollAnimation = [AnimationLoader loadPlistForAnimationWithName:@"SlideAnim" inFileNamed:@"BadGuyAnim"];
        
    }
    //TODO add sprite sheet for the enemy and implement same for it -- added for testing purposes - rev13
    else{
        self.runningAnim = [AnimationLoader loadPlistForAnimationWithName:@"RunAnim" inFileNamed:@"BadGuyAnim"];
        runAnimation = [AnimationLoader loadPlistForAnimationWithName:@"RunAnim" inFileNamed:@"GoodGuyAnim"];
        goInAnimation = [AnimationLoader loadPlistForAnimationWithName:@"GetInAnim" inFileNamed:@"GoodGuyAnim"];
        goOutAnimation = [AnimationLoader loadPlistForAnimationWithName:@"GetOutAnim" inFileNamed:@"GoodGuyAnim"];
        self.rollAnimation = [AnimationLoader loadPlistForAnimationWithName:@"SlideAnim" inFileNamed:@"GoodGuyAnim"];
        
    }
    
    
    
    // declare actions
    self.runAction = [CCActionRepeatForever  actionWithAction:[CCActionAnimate actionWithAnimation:runAnimation]];
    
    self.jumpAction = [CCActionSpawn actions:
                       //[CCActionAnimate actionWithAnimation:self.jumpAnimation],
                       [CCActionJumpBy actionWithDuration:kMessengerJumpDuration
                                                 position:CGPointZero
                                                   height:kMessengerJumpHeight jumps:1],
                       nil];
    
    self.slideAction = [CCActionSequence actions:
                        
                        [CCActionCallFunc actionWithTarget:self selector:@selector(setupRollingPhysicsBody)],
                        [CCActionAnimate actionWithAnimation:goInAnimation],
                        [CCActionCallFunc actionWithTarget:self selector:@selector(scaleToRollingAnimation)],
                        
                        [CCActionAnimate actionWithAnimation:self.rollAnimation],
                        [CCActionAnimate actionWithAnimation:self.rollAnimation],
                        [CCActionAnimate actionWithAnimation:self.rollAnimation],
                        [CCActionSpawn actions:
                         [CCActionAnimate actionWithAnimation:goOutAnimation],
                         [CCActionCallFunc actionWithTarget:self selector:@selector(setupNormalPhysBody)],
                         nil],
                        nil];
    
    self.slideAnim =[CCActionSequence actions:
    
    [CCActionAnimate actionWithAnimation:goInAnimation],
    
    [CCActionAnimate actionWithAnimation:self.rollAnimation],
    [CCActionAnimate actionWithAnimation:self.rollAnimation],
    [CCActionAnimate actionWithAnimation:self.rollAnimation],
     [CCActionAnimate actionWithAnimation:goOutAnimation],
    nil];

    
    
}

//updates
-(void) passSecondWithDelta:(CCTime) delta {
    self.secondsPassedSinceStart += delta;
}

//phys body and sprite frame setups

-(void) setupNormalPhysBody
{
    self.scale = kMessengerScale;
    int num = 10;
    CGPoint* shapeArr = malloc(sizeof(CGPoint)*num);
    
    shapeArr[0] = ccp(25.2f, 30.2f);
    shapeArr[1] = ccp(32.1f, -20.0f);
    shapeArr[2] = ccp(29.4f, -37.5f);
    shapeArr[3] = ccp(27.4f, -52.8f);
    shapeArr[4] = ccp(23.9f, -59.4f);
    shapeArr[5] = ccp(3.6f, -66.6f);
    shapeArr[6] = ccp(-84.9f, -66.2f);
    shapeArr[7] = ccp(-1.3f, 36.6f);
    shapeArr[8] = ccp(9.5f, 38.6f);
    shapeArr[9] = ccp(22.4f, 35.4f);
    
    for(int i=0; i< num; i++)
    {
        shapeArr[i] = ccp(shapeArr[i].x + self.offset.x, shapeArr[i].y + self.offset.y);
    }
    
    double scale = 0.8;
    for(int i=0; i< num; i++)
    {
        shapeArr[i] = ccp(shapeArr[i].x*scale, shapeArr[i].y*scale);
    }
    
    
    self.physicsBody = [CCPhysicsBody bodyWithPolygonFromPoints:shapeArr count:num cornerRadius:10];
    self.physicsBody.sensor = YES;
    self.physicsBody.collisionType = @"player";
    
    free(shapeArr);
}

-(void) setupRollingPhysicsBody
{
    
    self.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:20 andCenter:ccp(90, 35)];
    self.physicsBody.sensor = YES;
    self.physicsBody.collisionType = @"player";
}

-(void) scaleToRollingAnimation
{
    self.scale = kMessengerScale * 3;
}

-(void)roll
{
    [self setupRollingPhysicsBody];
    [self runAction:[CCActionSequence actions:[CCActionAnimate actionWithAnimation:self.rollAnimation],
                     [CCActionAnimate actionWithAnimation:self.rollAnimation],
                     nil]];
}

//restoration methods
-(void) restoreToNormalScale
{
    self.scale = kMessengerScale;
}

-(void)restoreKikback
{
    self.lastHitObstacle = nil;
    [self speedToNormalForward];
    NSLog(@"restore kickback");
}

- (void) speedToNormal{
    CGPoint turboSpeed = kMessengerInitialMaxSpeed;
    self.currentSpeed =  ccp(turboSpeed.x * self.currentSpeed.x/ ABS(self.currentSpeed.x), 0);
}

- (void) speedToNormalForward{
    self.currentSpeed = kMessengerInitialMaxSpeed;
}

- (void) speedToKickback{
    CGPoint turboSpeed = kMessengerKickbackSpeed;
    self.currentSpeed =  ccp(turboSpeed.x * -self.currentSpeed.x/ ABS(self.currentSpeed.x), 0);
}

- (void) speedToTurbo{
    CGPoint turboSpeed = kMessengerTurboSpeed;
    self.currentSpeed =  ccp(turboSpeed.x * self.currentSpeed.x/ ABS(self.currentSpeed.x), 0);
    //self.currentSpeed = kMessengerTurboSpeed;
}



@end


